package com.ideal.manage.esms.service.monitor;

import com.alibaba.fastjson.JSONObject;
import com.ideal.manage.esms.bean.esms.EsmsIntegration;
import com.ideal.manage.esms.bean.esms.QEsmsIntegration;
import com.ideal.manage.esms.bean.project.ProjectManage;
import com.ideal.manage.esms.jpa.JpaRepositoryImpl;
import com.ideal.manage.esms.service.ElasticsearchService;
import com.ideal.manage.esms.service.IntegrationService;
import com.ideal.manage.esms.util.IntegrationUtils;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.InternalDateHistogram;
import org.elasticsearch.search.aggregations.metrics.avg.InternalAvg;
import org.elasticsearch.search.aggregations.metrics.max.InternalMax;
import org.elasticsearch.search.aggregations.metrics.min.InternalMin;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregationBuilder;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.math.BigDecimal;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Service
@Transactional
public class MonitorBlockHistoryService {

    @Autowired
    private EntityManager entityManager;
    private JpaRepositoryImpl<ProjectManage, String> projectManageRepository;
    private JpaRepositoryImpl<EsmsIntegration, Long> integrationRepository;
    @Autowired
    private IntegrationService integrationService;
    @Autowired
    private ElasticsearchService elasticsearchService;
    @Autowired
    private TransportClient transportClient;

    @PostConstruct
    public void init() {
        this.projectManageRepository = new JpaRepositoryImpl<>(ProjectManage.class, entityManager);
        this.integrationRepository = new JpaRepositoryImpl<EsmsIntegration, Long>(EsmsIntegration.class, entityManager);
    }

    /**
     * 历史数据
     *
     * @param id        设备id
     * @param objType   测点类别
     * @param name      测点名称
     * @param ranges    时间范围
     * @param frequency 显示密度 小时 15分钟
     * @param showType  显示类别 //平均值，最大值 最小值 当前无效
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return
     */
    public JSONObject historyBlockDataEquipment(String id, int objType, String name, String ranges,
                                                String frequency, String showType, String startTime, String endTime) {
        JSONObject r = new JSONObject();
        // 2. 获取当前设备
        ProjectManage projectManage = projectManageRepository.findOne(id);
        if (projectManage == null) {
            return r;
        }
        // 4. 获取时间
        Tuple<LocalDateTime, LocalDateTime> dateRange = Utils.calDateRange(ranges, startTime, endTime);
        if (dateRange == null) {
            return r;
        }

        String title = String.format("%s %s-%s", projectManage.getName(),
                dateRange.v1().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")),
                dateRange.v2().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        r.put("title", title);
        Date startDate = Date.from(dateRange.v1().toInstant(ZoneOffset.of("+8")));
        Date endDate = Date.from(dateRange.v2().toInstant(ZoneOffset.of("+8")));
        switch (objType) {
            case 1:
                //电费
                r.putAll(getHistoryElectricQuantity(name, ranges, frequency, showType, startDate, endDate));
                break;
            case 2:
                //能量
                r.putAll(getHistoryEnergy(name, ranges, frequency, startDate, endDate));
                break;
            case 3:
                //效率
                r.putAll(getHistoryEfficiency(name, ranges, frequency, showType, startDate, endDate));
                break;
        }
        return r;
    }

    protected JSONObject queryModbus(String name, String ranges, String frequency, String showType, Date startDate, Date endDate) {
        Map<String, Integer> nameMapping = new HashMap<>();
        nameMapping.put("AB线电压", 2000);
        nameMapping.put("BC线电压", 2001);
        nameMapping.put("CA线电压", 2002);
        nameMapping.put("直流母线电压", 2009);

        nameMapping.put("A相电流", 2003);
        nameMapping.put("B相电流", 2004);
        nameMapping.put("C相电流", 2005);
        nameMapping.put("直流母线电流", 2010);
        Double xishu = 1.0;
        Integer typeId = nameMapping.getOrDefault(name, 0);
        ChartUtils.AggregationCondition condition = ChartUtils.buildCondition(frequency, ranges);
        JSONObject r = condition.defaultData;
        if (typeId == 0) {
            return r;
        }
        if (2000<=typeId &&typeId<=2014) {
            xishu = 0.1;
        }
        ESValueSourceAggregation aggregationBuilder = ChartUtils.getAggregation(showType);
        if (aggregationBuilder == null) {
            return r;
        }

        elasticsearchService.aggregation(QueryBuilders.boolQuery()
                        .filter(QueryBuilders.existsQuery(String.valueOf(typeId)))
                        .filter(QueryBuilders.rangeQuery("time").gte(startDate.getTime()).lte(endDate.getTime())),
                condition.interval, aggregationBuilder, (filedName, time, val) -> {
                    r.put(DateTimeFormat.forPattern(condition.fmt).print(time), val);
                }, String.valueOf(typeId));
        //2000-2014 val需要*0.1
        for(String s : r.keySet()){
            Double dval = Utils.halfUp(r.getDoubleValue(s)*xishu);
            r.put(s,String.valueOf(dval));
        }
        return r;
    }

    protected JSONObject getHistoryEfficiency(String name, String ranges, String frequency, String showType, Date startDate, Date endDate) {
        return this.queryModbus(name, ranges, frequency, showType, startDate, endDate);
    }

    protected JSONObject getHistoryEnergy(String name, String ranges, String frequency, Date startDate, Date endDate) {
        JSONObject r;
        String sql = "SELECT DATE_FORMAT(`cal_time`, '%d %H:%i') AS time, sum(val)" +
                " FROM esms_integration WHERE type=? AND cal_time BETWEEN ? AND ?";
        switch (frequency) {
            case "15":
                r = Utils.getFifteenMinutes();
                break;
            case "hour":
                r = Utils.getHour();
                sql = "SELECT DATE_FORMAT(`cal_time`, '%Y-%m-%d %H') AS time, sum(val)" +
                        " FROM esms_integration WHERE type=? AND cal_time BETWEEN ? AND ?  GROUP BY time";
                break;
            case "day":
                r = Utils.getDay(ranges);
                sql = "SELECT DATE_FORMAT(`cal_time`, '%Y-%m-%d') AS time, sum(val)" +
                        " FROM esms_integration WHERE type=? AND cal_time BETWEEN ? AND ?  GROUP BY time";
                break;
            case "month":
                r = Utils.getMonth();
                sql = "SELECT DATE_FORMAT(`cal_time`, '%Y-%m') AS time, sum(val)" +
                        " FROM esms_integration WHERE type=? AND cal_time BETWEEN ? AND ? GROUP BY time";
                break;
            default:
                r = new JSONObject();
                return r;
        }

        Query qry = entityManager.createNativeQuery(sql);
        qry.setParameter(2, startDate);
        qry.setParameter(3, endDate);
        switch (name) {
            case "充电量":
                qry.setParameter(1, "cdl");
                break;
            case "放电量":
                qry.setParameter(1, "fdl");
                break;
            default:
                return r;
        }
        List<Object[]> result = qry.getResultList();
        for (Object[] rs : result) {
            r.put((String) rs[0], rs[1]);
        }
        //积分 特别累加
        switch (frequency) {
            case "hour":
                List<String> list = new ArrayList<>(r.keySet());
                Collections.sort(list);
                double sum = 0.0;
                for (int i=0; i<result.size(); i++) {
                    String key = list.get(i);
                    sum += r.getDoubleValue(key);
                    r.put(key, sum);
                }
                break;
        }
        return r;

    }

    protected JSONObject getHistoryElectricQuantity(String name, String ranges, String frequency, String showType, Date startDate, Date endDate) {
        return this.queryModbus(name, ranges, frequency, showType, startDate, endDate);
    }
}
